package meta.api.web.file.presentation;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import meta.api.web.account.businessinfo.UserInfo;
import meta.api.web.common.util.ApiUtil;
import meta.api.web.file.businesscontrol.FileMngBusiCtrl;
import meta.api.web.file.businessinfo.FileInfo;
import meta.api.web.file.businessinfo.MetadataInfo;
import meta.api.web.file.presentation.form.FileListResult;
import meta.api.web.file.presentation.form.MetadataForm;
import meta.common.log.CmnLogger;
import meta.common.msg.MessageConst;
import meta.common.util.DateUtil;
import meta.common.util.JsonUtil;
import meta.common.util.StrUtil;
import meta.common.util.WebUtil;

@Controller
@RequestMapping(value="api/file")
@Tag(name = "文件管理机能", description = "文件管理机能")
public class FileMngController {

    private static final CmnLogger logger = CmnLogger.getLogger(FileMngController.class);

    private static final String FUNC_NM = "文件管理机能";

    private static final String ERROR_MSG_DATA_ERROR = "请求数据错误";
    private static final String ERROR_MSG_GET_LIST_ERROR = "获取文件列表失败";
    private static final String ERROR_MSG_SAVE_ERROR = "保存文件失败";
    private static final String ERROR_MSG_DELETED_ERROR = "文件已删除";
    private static final String ERROR_MSG_GET_ERROR = "获取文件失败";
    private static final String ERROR_MSG_MODIFY_ERROR = "修改文件属性失败";
    private static final String ERROR_MSG_DELETE_ERROR = "删除文件失败";

    @Autowired
    private FileMngBusiCtrl fileMngBusiCtrl;

    /**
     * 获取文件列表
     * 
     * @param req 请求
     * @param res 响应
     * @param current 当前页
     * @param pageSize 每页记录数
     * @return
     * @throws Exception 异常
     */
    @PostMapping(value="/list")
    @Operation(tags = "获取文件列表", description = "获取文件列表")
    public String list(HttpServletRequest req, HttpServletResponse res,
            @RequestParam(value = "current", required = false) Integer current,
            @RequestParam(value = "pageSize", required = false) Integer pageSize) throws Exception {
        ApiUtil.callApiLog(req, FUNC_NM, "获取文件列表", null);

        MetadataInfo inputMetadata = JsonUtil.toObj(ApiUtil.readTxtBody(req), MetadataInfo.class);
        if (inputMetadata == null) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_DATA_ERROR);
            return null;
        }

        int total;
        List<FileInfo> fileInfoList= new ArrayList<FileInfo>();
        try {
            // 取得登录用户详细情报
            UserInfo loginUser = WebUtil.getLoginUser(req);

            // 获取文件总件数
            total = fileMngBusiCtrl.getFileTotal(inputMetadata, loginUser.getId());

            // 获取文件列表
            if (total > 0) {
                fileInfoList = fileMngBusiCtrl.getFileList(inputMetadata, loginUser.getId(), current, pageSize);
            }

            FileListResult result = new FileListResult();
            result.setTotal(total);
            result.setList(fileInfoList);

            ApiUtil.setJsonResponse(res, JsonUtil.toJsonStr(result));
        } catch (Exception e) {
            logger.log(MessageConst.MSG_01090001, null, e);
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_GET_LIST_ERROR);
        }

        return null;
    }

    /**
     * 上传文件
     * 
     * @param req 请求
     * @param res 响应
     * @param file 文件
     * @param filename 文件名
     * @param tags 标签
     * @param share 是否共享
     * @param type 文件类型
     * @param directory 文件目录
     * @param remarks 备注
     * @return
     * @throws Exception 异常
     */
    @PostMapping(value="/upload")
    @Operation(tags = "上传文件", description = "上传文件")
    public String upload(HttpServletRequest req, HttpServletResponse res,
            @RequestParam(value = "file", required = true) MultipartFile file,
            @RequestParam(value = "filename", required = false) String filename,
            @RequestParam(value = "tags", required = false) String tags,
            @RequestParam(value = "share", required = false) boolean share,
            @RequestParam(value = "type", required = false) String type,
            @RequestParam(value = "directory", required = false) String directory,
            @RequestParam(value = "remarks", required = false) String remarks) throws Exception {
        ApiUtil.callApiLog(req, FUNC_NM, "上传文件", null);

        // 取得登录用户详细情报
        UserInfo loginUser = WebUtil.getLoginUser(req);

        if (StrUtil.isEmpty(filename)) {
            filename = file.getOriginalFilename();
        }

        String newfilename = loginUser.getId() + "_" + DateUtil.toStrForDwMs(new Date()) + "_" + filename;

        FileInfo inputFileInfo = new FileInfo();
        // 文件名
        inputFileInfo.setFilename(newfilename);
        // URL
        inputFileInfo.setUrl("/api/file/" + newfilename);
        // 字节长度
        inputFileInfo.setLength(file.getSize());
        // 元数据
        MetadataInfo metadata = new MetadataInfo();
        metadata.setName(filename);
        metadata.setTags(tags);
        metadata.setShared(share);
        metadata.setDirectory(directory);
        metadata.setRemarks(remarks);
        metadata.setType(type);
        metadata.setUserid(loginUser.getId());
        inputFileInfo.setMetadata(metadata);

        // 保存文件
        try {
            fileMngBusiCtrl.saveFile(inputFileInfo, file.getBytes());
        } catch (Exception e) {
            logger.log(MessageConst.MSG_01090001, null, e);
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_SAVE_ERROR);
            return null;
        }

        // 获取文件信息
        FileInfo outputFileInfo = fileMngBusiCtrl.getFileByFilename(newfilename, loginUser.getId());
        if (outputFileInfo == null) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_GET_ERROR);
            return null;
        }

        ApiUtil.setJsonResponse(res, JsonUtil.toJsonStr(outputFileInfo));
        return null;
    }

    /**
     * 获取文件
     * 
     * @param req 请求
     * @param res 响应
     * @param path 文件路径
     * @return
     * @throws Exception 异常
     */
    @GetMapping(value="/{path}")
    @Operation(tags = "获取文件", description = "获取文件")
    public String getFile(HttpServletRequest req, HttpServletResponse res,
            @PathVariable("path") String path) throws Exception {
        ApiUtil.callApiLog(req, FUNC_NM, "获取文件", null);

        // 取得登录用户详细情报
        UserInfo loginUser = WebUtil.getLoginUser(req);

        // 检证文件是否存在
        if (!fileMngBusiCtrl.checkIsFileExisted(path, null)) {
            ApiUtil.setNotFoundResponse(req, res);
            return null;
        }

        // 检证文件是否逻辑删除
        if (fileMngBusiCtrl.checkIsFileExisted(path, false)) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_DELETED_ERROR);
            return null;
        }

        // 取得文件情报
        FileInfo outputFileInfo = fileMngBusiCtrl.getFileByFilename(path, loginUser.getId());
        if (outputFileInfo == null) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_GET_ERROR);
            return null;
        }

        // output
        WebUtil.outputBin(res, outputFileInfo.getFilename(), outputFileInfo.getFileContent());
        return null;
    }

    /**
     * 修改文件属性内容
     * 
     * @param req 请求
     * @param res 响应
     * @param path 文件路径
     * @return
     * @throws Exception 异常
     */
    @PatchMapping(value="/{path}")
    @Operation(tags = "修改文件属性内容", description = "修改文件属性内容")
    public String modifyFile(HttpServletRequest req, HttpServletResponse res,
            @PathVariable("path") String path) throws Exception {
        ApiUtil.callApiLog(req, FUNC_NM, "修改文件属性内容", null);

        MetadataForm inputMetadata = JsonUtil.toObj(ApiUtil.readTxtBody(req), MetadataForm.class);
        if (inputMetadata == null) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_DATA_ERROR);
            return null;
        }

        inputMetadata.rebuildTags();

        // 取得登录用户详细情报
        UserInfo loginUser = WebUtil.getLoginUser(req);

        // 检证文件是否存在
        if (!fileMngBusiCtrl.checkIsFileExisted(path, null)) {
            ApiUtil.setNotFoundResponse(req, res);
            return null;
        }

        // 检证文件是否逻辑删除
        if (fileMngBusiCtrl.checkIsFileExisted(path, false)) {
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_DELETED_ERROR);
            return null;
        }

        // 检证权限
        if (!fileMngBusiCtrl.checkIsFileOwner(path, loginUser.getId())) {
            ApiUtil.setForbiddenResponse(req, res);
            return null;
        }

        // 修改文件属性内容
        try {
            fileMngBusiCtrl.updateFile(path, inputMetadata, loginUser.getId());
            ApiUtil.setEmptyJsonResponse(res);
        } catch (Exception e) {
            logger.log(MessageConst.MSG_01090001, null, e);
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_MODIFY_ERROR);
        }

        return null;
    }

    /**
     * 删除文件
     * 
     * @param req 请求
     * @param res 响应
     * @param path 文件路径
     * @return
     * @throws Exception 异常
     */
    @DeleteMapping(value="/{path}")
    @Operation(tags = "删除文件", description = "删除文件")
    public String deleteFile(HttpServletRequest req, HttpServletResponse res,
            @PathVariable("path") String path) throws Exception {
        ApiUtil.callApiLog(req, FUNC_NM, "删除文件", null);

        // 取得登录用户详细情报
        UserInfo loginUser = WebUtil.getLoginUser(req);

        // 检证文件是否存在
        if (!fileMngBusiCtrl.checkIsFileExisted(path, null)) {
            ApiUtil.setNotFoundResponse(req, res);
            return null;
        }

        // 检证权限
        if (!fileMngBusiCtrl.checkIsFileOwner(path, loginUser.getId())) {
            ApiUtil.setForbiddenResponse(req, res);
            return null;
        }

        // 删除文件
        try {
            fileMngBusiCtrl.deleteFileByFilename(path, loginUser.getId());
            ApiUtil.setEmptyJsonResponse(res);
        } catch (Exception e) {
            logger.log(MessageConst.MSG_01090001, null, e);
            ApiUtil.setErrorJsonResponse(res, ERROR_MSG_DELETE_ERROR);
        }

        return null;
    }
}
